local jass = require 'jass.common'
local japi = require 'jass.japi'
local message  = require 'jass.message'

--[[
  
    添加位移buff 时 如果 没有提前派发 打断位移事件 则根据 位移的等级 来进行 覆盖 或 抵消

    添加成功时 如果目标 被禁锢 则无法位移 否则 给单位 位移状态标记

    禁锢效果可以打断位移

    受到打断效果将会停止当前位移

]]

ac.buff("位移"){

    level = 1,

    pulse = 0.03,

    displace = true,

    -- 目标
    target = ac.point(0,0),
    -- 弧度
    orc = 0.00,
    -- 追踪 （不追踪目标跑远了会停下）
    homing = true, 
    -- 速度
    speed = 1000,
    -- 加速度
    accele = 0,

    on_add = function(self)
        local unit = self.owner 
        if unit:has_restriction '禁锢' then 
            self:remove()
            return false
        end 
        local launch = unit:get_point()
        local launch_height = launch:get_height() + unit:get_height()
        local impact = self.target:get_point()
        local impact_height = impact:get_height()
        if self.target.type == 'point' then 
            impact_height = impact_height + self.target.z
        elseif self.target.type == 'unit' then 
            impact_height = impact_height + self.target:get_height()
        end 
        local distance = launch * impact    -- 水平距离
        local highest = distance * self.orc + math.lerp(launch_height, impact_height, 0.5) -- 最高点
        local length = math.sqrt((launch_height - impact_height) ^ 2 + (distance) ^ 2)  -- 总位移
        if length <= 0 then 
            self:notify("on_finish")
            self:remove()
            return 
        end 
        self.highest = highest
        self.length = length
        self.launch = launch
        self.launch_height = launch_height
        self.impact = impact
        self.impact_height = impact_height
        self.current_point = launch
        self.current_height = launch_height
        self.moved = 0
        self.progress = 0
        if self.speed < 0 then 
            self.speed = self.length / self.pulse
        elseif self.speed == 0 then 
            self.speed = self.length
        end 
        self.has_homing = self.homing
        self.has_revise = true
        self.has_finish = true  -- 派发结束事件
        self.has_resume = true
        self.has_launch = true
        self.has_unmove = true
        unit:notify("单位-打断位移", unit)
        unit:add_restriction "位移"
        unit:add_restriction "幽灵"
        if self.stun_flag then 
            unit:add_restriction "晕眩"
            self.has_stun = true
        end
        self.triggers = {}
        self.triggers[1] = unit:on "单位-打断位移" (function(_, _, flag)
            self.has_resume = (flag == true)    -- 有这个标记代表恢复默认高度
            self:notify("on_break")
            self:remove()
        end)
        if self.target.type == 'unit' and self.has_homing then  
            self.triggers[2] = self.target:on "单位-死亡" (function()
                self.has_homing = false 
            end)
        end
        self:notify("on_launch")
    end,

    on_pulse = function(self)
        local unit = self.owner 
        local target = self.target
        local launch = self.launch
        local launch_height = self.launch_height
        local impact = self.impact
        local impact_height = self.impact_height
        local highest = self.highest
        local length = self.length
        local current_point = self.current_point
        local current_height = self.current_height
        local moved = self.moved 
        local progress = self.progress
        local speed = self.speed
        local accele = self.accele
        local pulse = self.pulse
        local orc = self.orc 
        if self.has_homing then 
            if self.has_revise then 
                local point = self.target:get_point()
                local height = point:get_height()
                if (math.sqrt((impact_height - height) ^ 2 + (impact * point) ^ 2)) <= 16 then 
                    -- 进行修正
                    highest = launch * point * (orc) + math.lerp(launch_height, height, 0.5)
                    length = math.sqrt((launch_height - height) ^ 2 + (launch * point) ^ 2)
                    impact = point
                    impact_height = height
                    if self.target.type == 'point' then 
                        impact_height = impact_height + self.target.z
                    elseif self.target.type == 'unit' then 
                        impact_height = impact_height + self.target:get_height()
                    end 
                    self.highest = highest
                    self.length = length 
                    self.impact = impact
                    self.impact_height = impact_height
                else
                    self.has_revise = false
                end
            end
        end 

        if not self.has_revise then 
            impact = self.target:get_point()
            impact_height = impact:get_height()
            if self.target.type == 'point' then 
                impact_height = impact_height + self.target.z
            elseif self.target.type == 'unit' then 
                impact_height = impact_height + self.target:get_height()
            end 
        end

        if length <= 0 then
            self:notify("on_finish")
            self:remove()
            return
        end 

        speed = speed + accele * pulse
        moved = moved + speed * pulse

        if self.has_revise then 
            -- 抛物线移动
            progress = math.min(moved / length, 1)
            current_point = launch:lerp(impact, progress)
            if orc ~= 0 then 
                current_height = math.parabola(launch_height, highest, impact_height, progress)
            else 
                current_height = math.lerp(launch_height, impact_height, progress)
            end
        else 
            -- 追踪移动
            length = math.sqrt((current_height - impact_height) ^ 2 + (current_point * impact) ^ 2)
            progress = math.min((speed * pulse) / length, 1)
            current_point = current_point:lerp(impact, progress)
            current_height = math.lerp(current_height, impact_height, progress)
        end 
        if self:notify("on_move", current_point, current_height) == false then 
            self:remove()
            return 
        end 
        if self.removed then
            return
        end
        self.current_height = current_height
        self.current_point = current_point
        self.progress = progress
        self.moved = moved
        self.length = length
        self.speed = speed
        unit:set_point( current_point )
        unit:set_height( current_height - current_point:get_height() )
        if self.progress == 1 then 
            self:notify("on_finish")
            self:remove()
        end 
    end,

    on_remove = function(self)
        local unit = self.owner 
        if self.triggers then 
            for i = 1, #self.triggers do 
                self.triggers[i]:remove()
            end
        end 
        if self.has_unmove then 
            unit:remove_restriction "位移"
            unit:remove_restriction "幽灵"
        end 
        if self.has_stun then 
            unit:remove_restriction "晕眩"
        end
        if self.has_resume then 
            unit:set_height( unit:get_default_height() )
        end 
        if self.has_launch then 
            self:notify("on_stop")
        end
    end,

    on_cover = function(self)
        self.has_resume = false
        return true
    end,
}